import utime
########人脸识别的库
import network
import time
import sensor
#import urequests
import lcd
import sys
from Maix import GPIO
from fpioa_manager import fm
from board import board_info
import KPU as kpu
import image

###########################
####定时器的库

import time
from machine import Timer

####定时器的库
############串口发送的库
from fpioa_manager import fm
from machine import UART
from board import board_info

############# 文件操作库
import os
import requests
#from requests import post
#############

############# IIS DAC PA #########
from fpioa_manager import *
from Maix import I2S, GPIO
import audio
##############
#import _thread
##############

import gc
###############
#############定时器回调函数######

timer_status = 0 ## 0表示 进入网络连接的函数 1 表示进入BIOS的函数 2表示进入检测模式
enter_status = 0 ## 是否进入 网络设置函数和密码输入
def on_timer(timer):
    gc.collect() ###回收辣鸡
    if timer_status == 2:
        print("Heap ram:",gc.mem_free())
        print("alloc Heap ram:",gc.mem_alloc())
        print("total :",gc.mem_alloc()+gc.mem_free())
        if(nic.isconnected() == False):
            WifiConnecting(nic)
    elif timer_status == 1 :
        print("time up")
        if key.value() == 0: # 等待按键按下
            tim0.stop()
            lcd.clear()
            lcd.draw_string(100,100, "entering 'INPUT MOD'...",lcd.RED,lcd.BLACK)  
            time.sleep_ms(1000)
            InputMode()
    elif timer_status == 0: 
        print("time up")
        if key.value() == 0: # 等待按键按下
            tim0.stop()
            lcd.clear()
            lcd.draw_string(100,100, "entering 'WifiConfig'...",lcd.RED,lcd.BLACK)  
            time.sleep_ms(1000)
            WifiConfig()
    #print("param:",timer.callback_arg())
    

#############定时器回调函数######

####将wifi账号密码导入flash###
def loadAccountPassword(deviceInfo):
    try:
        os.remove("/flash/deviceInfo.py") ##清空文件   
    ##添加
    except:
        print("no file!")
    fp = open("/flash/deviceInfo.py","w")
    fp.write(deviceInfo["account"])
    fp.write("\n")
    fp.write(deviceInfo["password"])
    fp.write("\n")
    fp.close()
    pass
##############################
def getAccountPassword():
    fp = open("/flash/deviceInfo.py","r+")
    deviceInfo = {"account":"","password":""}    
    while True:
        Str = fp.read(1)
        if Str == "\n":
            break
        deviceInfo["account"] += Str
    while True:
        Str = fp.read(1)
        if Str == "\n":
            break
        deviceInfo["password"]+= Str
    fp.close()
    return deviceInfo


def inputAccount(deviceInfo):
    uart_A.write(b'\xff\xff\xff')## mircoPython有小big 必须先用一个0xff覆盖掉
    uart_A.write("t0.txt=\"SSID\"")  ##文本内容
    uart_A.write(b'\xff\xff\xff')  ##结束字符
    lcd.clear()
    lcd.draw_string(20,100, "pls input 'SSID'",lcd.RED,lcd.BLACK)
    PlayIt("/flash/inputSSID.wav")
    uart_A.read()###清空串口缓存区
    while True:
        if uart_A.any(): ##判断是否为空
            read_data = uart_A.read()
            print("'SSID':",read_data)
            deviceInfo["account"]= read_data.decode('utf-8')
            return deviceInfo
def inputPassword(deviceInfo):

    uart_A.write(b'\xff\xff\xff')## mircoPython有小big 必须先用一个0xff覆盖掉
    uart_A.write("t0.txt=\"Password\"")  ##文本内容
    uart_A.write(b'\xff\xff\xff')  ##结束字符
    lcd.clear()
    lcd.draw_string(20,100, "pls input 'password'",lcd.RED,lcd.BLACK)
    PlayIt("/flash/inputPassword.wav")
    uart_A.read()
    while True:
        if uart_A.any(): ##判断是否为空
            read_data = uart_A.read()
            print("'password':",read_data)
            deviceInfo["password"]= read_data.decode('utf-8')
            return deviceInfo

 ##录入   
def InputMode():
    uart_A.write(b'\xff\xff\xff')## mircoPython有小big 必须先用一个0xff覆盖掉
    uart_A.write("dim=100")  ##文本内容
    uart_A.write(b'\xff\xff\xff')  ##结束字符
    lcd.clear()
    lcd.draw_string(50,50, "Input your studentID",lcd.RED,lcd.BLACK)
    sensor.run(1)
    uart_A.write(b'\xff\xff\xff')## mircoPython有小big 必须先用一个0xff覆盖掉
    uart_A.write("t0.txt=\"Student ID\"")  ##文本内容
    uart_A.write(b'\xff\xff\xff')  ##结束字符
    
    studentID = inputStuID()##阻塞型的
    PlayIt("/flash/inputFace.wav")
    while True: ######无退出函数 当录入完成后自行重启
        img = sensor.snapshot()
        lcd.display(img)
        #try:
            #read_str = read_data.decode('utf-8')
            #print(read_str)
        if uart_A.any() :
            read_data = uart_A.read()
            print(read_data)
            print(type(read_data))
            read_str = read_data.decode('utf-8')
            if  read_str == "takePhoto":
                img = img.compress(quality=80)
                #if True:
                try: 
                    response = requests.post("http://120.79.40.182:3090/device/info_input", data = img.to_bytes(), headers= {"student_id":studentID})
                    print(response.status_code)
                    if response.status_code == 200: 
                        print(response.status_code,":success!")
                        lcd.draw_string(50,50, "success!",lcd.RED,lcd.BLACK)
                        PlayIt("/flash/infoInputSucess.wav")
                        time.sleep(3)
                        InputMode()##递归连续录入
                    elif response.status_code == 402:
                        print(response.status_code, ":no face shows up")
                        lcd.draw_string(50,50, "no face shows up",lcd.RED,lcd.BLACK)
                        PlayIt("/flash/tryAgain.wav")
                        time.sleep(3)
                    elif response.status_code == 403:
                        print(response.status_code , ":there is something wrong with parameter!")
                        lcd.draw_string(50,50,  "there is something wrong with parameter!",lcd.RED,lcd.BLACK)
                        time.sleep(3)
                    elif response.status_code == 404:
                        print(response.status_code)
                        lcd.draw_string(50,50, "404 not find",lcd.RED,lcd.BLACK)
                        time.sleep(3)
                    else :
                        print("unknown errors")
                        lcd.draw_string(100,100, "unknown errors",lcd.RED,lcd.BLACK)
                        time.sleep(3)
                except:
                    PlayIt("/flash/tryAgain.wav")
                    print("can't post it ")
            else:
                print("check fail")
            ####用屏幕 开始驱动拍照
##网络设置
def WifiConfig():
    uart_A.write(b'\xff\xff\xff')## mircoPython有小big 必须先用一个0xff覆盖掉
    uart_A.write("dim=100")  ##文本内容
    uart_A.write(b'\xff\xff\xff')  ##结束字符
    deviceInfo = {"account":"","password":""}
    deviceInfo = inputAccount(deviceInfo)
    uart_A.write(b'\xff\xff\xff')## mircoPython有小big 必须先用一个0xff覆盖掉
    uart_A.write("t1.txt=\"\"")  ##文本内容
    uart_A.write(b'\xff\xff\xff')  ##结束字符
    lcd.draw_string(20,20,deviceInfo["account"],lcd.RED,lcd.BLACK)
    print(deviceInfo)
    deviceInfo = inputPassword(deviceInfo)
    print(deviceInfo)
    import os
    time.sleep(3)
    loadAccountPassword(deviceInfo)
    test = getAccountPassword()
    lcd.clear()
    lcd.draw_string(20,50, "Wifi setting is successful",lcd.RED,lcd.BLACK)
    lcd.draw_string(20,80, ", please restart the device",lcd.RED,lcd.BLACK)
    lcd.draw_string(20,100,deviceInfo["account"],lcd.RED,lcd.BLACK)
    lcd.draw_string(20,120,deviceInfo["password"],lcd.RED,lcd.BLACK)
    while True:
        print(test)
##网络设置

def inputStuID():
    lcd.clear()
    lcd.draw_string(100,100, "pls input your student ID",lcd.RED,lcd.BLACK)
    PlayIt("/flash/inputStudentID.wav")
    uart_A.read()###清空串口缓存区
    while True:
        if uart_A.any() :
            read_data = uart_A.read()
            print("Student ID:",read_data)
            studentID = read_data.decode('utf-8')
            return studentID
def takePhoto():
    img = sensor.snapshot()
    lcd.display(img)
    img = img.compress(quality=80)
    lcd.draw_string(100,100, "..checking...waitting...",lcd.RED,lcd.BLACK)
    try:
        response = post("http://120.79.40.182:3090/", data = img.to_bytes(), headers= {'Command':'informationInput','Studentid':'2018215146'})
        print(response.content)
    except:
        print("can't post it ")



def Dectect():
    uart_A.write(b'\xff\xff\xff')## mircoPython有小big 必须先用一个0xff覆盖掉
    uart_A.write("dim=0")  ##文本内容
    uart_A.write(b'\xff\xff\xff')  ##结束字符
    j = 0
    sensor.run(1)
    while True:
        #sensor.snapshot().save("/sd/tempPhoto")
        img = sensor.snapshot()
        try:
            code = kpu.run_yolo2(task, img)
        except:
            #lcd.clear()
            #lcd.draw_string(100,100, "..kmodel wrong...",lcd.RED,lcd.BLACK)
            #while True:
                #print("kmodel wrong")
            code = None
            pass
        
        if code :
            j = j + 1
            if j == 5:
                j = 0
                x =  code[0]
                #for i in code:
                lcd.draw_string(100,100, "..checking...waitting...",lcd.RED,lcd.BLACK)
                COUNT1 = utime.ticks_ms()
                img_Send = img.compressed(quality=80)
                #print(len(img_Send.to_bytes()))
                #try:
                try:
                #if True:
                    response = requests.post("http://120.79.40.182:3090/device/check_authority", data = img_Send.to_bytes(), headers= {'room_id':roomId})
                    if response.content != '':
                        if response.status_code == 200:
                            jsonContent = response.json()
                            print(jsonContent["authority"])
                            if jsonContent["student_id"] == "unknown":
                                lcd.draw_string(100,20, "fail!",lcd.RED,lcd.BLACK)
                                PlayIt("/flash/cannotPost.wav")
                                print("no face! fail!",gc.mem_free())
                            elif jsonContent["authority"] == True:
                                lcd.draw_string(100,20, "success!",lcd.RED,lcd.BLACK)
                                print(jsonContent["student_id"])
                                lcd.draw_string(100,40, "student ID: ",lcd.RED,lcd.BLACK)
                                lcd.draw_string(100,60, jsonContent["student_id"],lcd.RED,lcd.BLACK)
                                PlayIt("/flash/allow.wav")
                                COUNT2 = utime.ticks_ms()
                                print(COUNT2-COUNT1)
                                LOCK.value(1)
                                ###加一个开锁
                                time.sleep(2)
                                LOCK.value(0)
                                
                            elif jsonContent["authority"] == False:
                               lcd.draw_string(100,20, "forbid!",lcd.RED,lcd.BLACK)
                               lcd.draw_string(100,40, "student ID: ",lcd.RED,lcd.BLACK)
                               lcd.draw_string(100,60, jsonContent["student_id"],lcd.RED,lcd.BLACK)
                               PlayIt("/flash/forbid.wav")
                               print("forbid!")
                               time.sleep(3)
                        if response.status_code == 402:
                            print(response.status_code, ":no face shows up")
                            lcd.draw_string(50,50, "no face shows up",lcd.RED,lcd.BLACK)
                            PlayIt("/flash/cannotPost.wav")
                            time.sleep(2)
                        if response.status_code == 403:
                            print(response.status_code)
                            #lcd.draw_string(50,50, "404 not find",lcd.RED,lcd.BLACK)
                            time.sleep(2)
                        if response.status_code == 404:
                            print("unknown errors")
                            #lcd.draw_string(100,100, "unknown errors",lcd.RED,lcd.BLACK)
                        
                    a = img.draw_rectangle( (51, 50, 200,135 ) , color = (0,255,0) )
                    lcd.display(img)
                    content_str = response.content.decode('utf-8')
                    #lcd.draw_string(50,50, content_str ,lcd.RED,lcd.BLACK)
                except:
                    #lcd.display(img)
                    print("can't post it")
                    PlayIt("/flash/cannotPost.wav")
                    #lcd.draw_string(50,50, "can't post it",lcd.RED,lcd.BLACK)
                    time.sleep(1)
        else:
            j = 0
            a = img.draw_rectangle( (51, 50, 200,135 ) , color = (0,255,0) )
            lcd.display(img)

def PlayIt(path):
    # init audio 
    print(path)
    player = audio.Audio(path = path)
    player.volume(100)
    wav_info = player.play_process(wav_dev)
    # config i2s according to audio info
    wav_dev.channel_config(wav_dev.CHANNEL_1, I2S.TRANSMITTER,resolution = I2S.RESOLUTION_16_BIT ,cycles = I2S.SCLK_CYCLES_32, align_mode = I2S.RIGHT_JUSTIFYING_MODE)
    wav_dev.set_sample_rate(wav_info[1])
    # loop to play audio
    while True:
        ret = player.play()
        if ret == None:
            print("format error")
            break
        elif ret==0:
            print("end")
            break
    player.finish()##释放内存
    


def WifiConnecting(nic):
    lcd.clear()
    lcd.draw_string(100,50, "Wifi is connecting...",lcd.RED,lcd.BLACK)
    lcd.draw_string(100,100, "please hold on...",lcd.RED,lcd.BLACK)
    while True:
        try:
            wifiInfo = getAccountPassword()
            nic.connect(wifiInfo["account"],wifiInfo["password"])
            print(nic.ifconfig())
            print("wifi connected?: ",nic.isconnected())
            if(nic.isconnected() == True):
                break
        except:
            time.sleep_ms(100)
            print("Wifi Connected fail!!")


###timer初始化###########
tim0 = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PERIODIC, period=1, unit=Timer.UNIT_S, callback=on_timer, arg=on_timer, start=False, priority=1, div=0)
print("period:",tim0.period())
###timer初始化###########

###########UART
fm.register(21,fm.fpioa.UART1_TX) ## 将IO21 22注册到串口 TX RX
fm.register(22,fm.fpioa.UART1_RX)
uart_A = UART(UART.UART1, 115200, 8, None, 1, timeout=1000, read_buf_len=4096)
###########UART

################BOOT
fm.register(board_info.BOOT_KEY, fm.fpioa.GPIOHS1)
key = GPIO(GPIO.GPIOHS1, GPIO.IN)
################BOOT

##################WIFI PASSWORD AND USERNAME

DeviceInfo = {"account":"HUA","password":"123456789"}
#WIFI_SSID = "HUA"
#WIFI_PASSWD = "123456789"
##################WIFI PASSWORD AND USERNAME
###########KPU INIT#########################
lcd.init()
task = kpu.load("/sd/facedetect.kmodel")
anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025) ##跟人脸识别模型有关
a = kpu.init_yolo2(task, 0.8, 0.3, 5, anchor)   #5 
img_lcd=image.Image()
#####I2S,DAC,D class PA#######
# register i2s(i2s0) pin
fm.register(34,fm.fpioa.I2S0_OUT_D1)
fm.register(35,fm.fpioa.I2S0_SCLK)
fm.register(33,fm.fpioa.I2S0_WS)
# init i2s(i2s0)
wav_dev = I2S(I2S.DEVICE_0)
##############################

###########KPU INIT#########################

# IO map for ESP32 on Maixduino
fm.register(25,fm.fpioa.GPIOHS10, force=True)#cs
fm.register(8,fm.fpioa.GPIOHS11, force=True)#rst
fm.register(9,fm.fpioa.GPIOHS12, force=True)#rdy
fm.register(28,fm.fpioa.GPIOHS13, force=True)#mosi
fm.register(26,fm.fpioa.GPIOHS14, force=True)#miso
fm.register(27,fm.fpioa.GPIOHS15, force=True)#sclk

#fm.register(8, fm.fpioa.GPIO0)
#wifi_en=GPIO(GPIO.GPIOHS11,GPIO.OUT)
# IO map for ESP32 on Maixduino
nic = network.ESP32_SPI(cs=fm.fpioa.GPIOHS10,rst=fm.fpioa.GPIOHS11,rdy=fm.fpioa.GPIOHS12, mosi=fm.fpioa.GPIOHS13,miso=fm.fpioa.GPIOHS14,sclk=fm.fpioa.GPIOHS15)

###########摄像头 INIT###########
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.run(0)
###########摄像头 INIT###########

##### device ID : room id
roomId = "YF103"###2333
#####
#help(open)

time.sleep(1)

##########自动垃圾回收#########
gc.enable()
#gc.disable()
#############################

###########锁的驱动###########
fm.register(23,fm.fpioa.GPIOHS2)
LOCK = GPIO(GPIO.GPIOHS2,GPIO.OUT)
#while True:
    #LOCK.value(1)
    #utime.sleep_ms(1)
    #LOCK.value(0)
    #utime.sleep_ms(1)
    
#############################

##############键盘复位##########
uart_A.write(b'\xff\xff\xff')## mircoPython有小big 必须先用一个0xff覆盖掉
uart_A.write("rest")  ##文本内容
uart_A.write(b'\xff\xff\xff')  ##结束字符
time.sleep(2)
uart_A.write(b'\xff\xff\xff')## mircoPython有小big 必须先用一个0xff覆盖掉
uart_A.write("dim=0")  ##文本内容
uart_A.write(b'\xff\xff\xff')  ##结束字符
###############################

##Wifi Config####
tim0.start()
timer_status = 0 ## 0表示 进入网络连接的函数 1 表示进入BIOS的函数
for i in range(1,10):
    lcd.clear()
    lcd.draw_string(50,100, "Press 'boot' , start 'WifiConfig MOD'",lcd.RED,lcd.BLACK)
    lcd.draw_string(100,50, "{:.0f}".format(10-i),lcd.RED,lcd.WHITE)
    time.sleep(1)
tim0.stop()
#################


###wifi连接部分
WifiConnecting(nic)
##########
###main######
while True:
    ##BIOS
    tim0.start()
    timer_status = 1 ## 0表示 进入网络连接的函数 1 表示进入BIOS的函数
    for i in range(1,10):
        lcd.clear()
        lcd.draw_string(50,100, "Press 'boot' , start Input Mode",lcd.RED,lcd.BLACK)
        lcd.draw_string(100,50, "{:.0f}".format(10-i),lcd.RED,lcd.WHITE)
        time.sleep(1)
    tim0.stop()
    ##BIOS
    ######定时器中断向量标志改为2 检测wifi是否断掉模式
    timer_status =2 
    tim0.start()
    ######
    ####正常模式
    Dectect()
    ####正常模式
        
